package com.meida.module.admin.provider.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.meida.common.constants.CommonConstants;
import com.meida.common.exception.OpenAlertException;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.mybatis.entity.EntityMap;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.utils.StringUtils;
import com.meida.common.utils.WebUtils;
import com.meida.module.admin.client.constants.AuthConstants;
import com.meida.module.admin.client.constants.BaseConstants;
import com.meida.module.admin.client.entity.BaseAccount;
import com.meida.module.admin.client.entity.BaseUser;
import com.meida.module.admin.client.model.UserAccount;
import com.meida.module.admin.provider.mapper.BaseUserAccountMapper;
import com.meida.module.admin.provider.service.BaseUserAccountService;
import com.meida.module.admin.provider.service.BaseUserService;
import com.meida.module.system.client.entity.BaseUserAccountLogs;
import com.meida.module.system.provider.mapper.BaseUserAccountLogsMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.Optional;

/**
 * @author zyf
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class BaseUserAccountServiceImpl extends BaseServiceImpl<BaseUserAccountMapper, BaseAccount> implements BaseUserAccountService {

    @Autowired
    private BaseUserAccountMapper baseUserAccountMapper;
    @Autowired
    private BaseUserAccountLogsMapper systemUserAccountLogsMapper;
    @Autowired
    private BaseUserService baseUserService;
    @Autowired
    private PasswordEncoder passwordEncoder;




    /**
     * 注册账号
     *
     * @param username
     * @param avatar
     * @param accontType
     * @param nickName
     * @return
     */
    @Override
    public BaseAccount register(String username, String avatar, String accontType, String nickName) {
        BaseAccount baseAccount = getUserAccount(username, null);
        if (ObjectUtils.isEmpty(baseAccount)) {
            //加密
            String encodePassword = passwordEncoder.encode(CommonConstants.DEF_PWD);
            baseAccount = new BaseAccount(username, encodePassword, accontType, nickName, avatar);
            baseUserAccountMapper.insert(baseAccount);
        }
        return baseAccount;
    }

    /**
     * 注册账号
     *
     * @param userId
     * @param account
     * @param password
     * @param accountType
     * @param status
     * @param domain
     * @param registerIp
     * @return
     */
    @Override
    public BaseAccount register(Long userId, String account, String password, String accountType, Integer status, String domain, String registerIp) {
        if (isExist(account, accountType, domain)) {
            // 账号已被注册
            throw new RuntimeException(String.format("account=[%s],domain=[%s]", account, domain));
        }
        //加密
        String encodePassword = passwordEncoder.encode(password);
        BaseAccount baseAccount = new BaseAccount(userId, account, encodePassword, accountType, domain, registerIp);
        baseAccount.setStatus(status);
        baseUserAccountMapper.insert(baseAccount);
        return baseAccount;
    }

    /**
     * 绑定账户
     */
    @Override
    public ResultBody bindAccount(Long userId, String accountName, String accountType, String nickName, String avatar) {
        Boolean isBind = false;
        CriteriaQuery cq = new CriteriaQuery(BaseAccount.class);
        BaseAccount systemAccount = getOne(cq.eq(true, "account", accountName));
        String message = "";
        if (ObjectUtils.isEmpty(systemAccount)) {
            String encodePassword = passwordEncoder.encode(CommonConstants.DEF_PWD);
            systemAccount = new BaseAccount(userId, accountName, encodePassword, accountType, nickName, avatar);
            isBind = save(systemAccount);
            message = "绑定成功";
        } else {
            QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
            queryWrapper.lambda()
                    .eq(BaseAccount::getUserId, userId)
                    .eq(BaseAccount::getAccount, accountName)
                    .eq(BaseAccount::getAccountType, accountType);
            int n = baseUserAccountMapper.delete(queryWrapper);
            if (n > 0) {
                message = "解绑成功";
            } else {
                return ResultBody.failed("请使用绑定账户进行解绑");
            }
        }
        Boolean qq = isExist(userId, BaseConstants.USER_ACCOUNT_TYPE_QQ);
        Boolean weibo = isExist(userId, BaseConstants.USER_ACCOUNT_TYPE_WEIBO);
        Boolean weixin = isExist(userId, BaseConstants.USER_ACCOUNT_TYPE_WEIXIN);
        EntityMap map = new EntityMap();
        map.put(BaseConstants.USER_ACCOUNT_TYPE_WEIXIN, weixin);
        map.put(BaseConstants.USER_ACCOUNT_TYPE_QQ, qq);
        map.put(BaseConstants.USER_ACCOUNT_TYPE_WEIBO, weibo);
        return ResultBody.ok(message, map);
    }

    /**
     * 注册账号
     *
     * @param accountName
     * @param password
     * @return
     */
    @Override
    public BaseAccount registerByMobile(String accountName, String password) {
        String avatar = CommonConstants.DEFAULT_USERHEAD;
        String accontType = BaseConstants.USER_ACCOUNT_TYPE_MOBILE;
        BaseAccount baseAccount = getUserAccount(accountName, accontType);
        if (ObjectUtils.isEmpty(baseAccount)) {
            //加密
            String encodePassword = passwordEncoder.encode(password);
            baseAccount = new BaseAccount(accountName, encodePassword, accontType, "", avatar);
            baseUserAccountMapper.insert(baseAccount);
        }
        return baseAccount;
    }

    /**
     * 支持系统用户名、手机号、email登陆
     *
     * @param username
     * @return
     */
    @Override
    public UserAccount login(String username) {
        if (StringUtils.isBlank(username)) {
            return null;
        }
        Map<String, String> headers = WebUtils.getHttpHeaders(WebUtils.getHttpServletRequest());
        // 第三方登录标识
        String thirdParty = headers.get(AuthConstants.HEADER_X_THIRDPARTY_LOGIN);
        BaseAccount account = null;
        // 账号返回数据
        UserAccount accountDto = null;
        QueryWrapper<BaseAccount> qw = new QueryWrapper();
        qw.lambda().eq(BaseAccount::getAccount, username);
        if (StringUtils.isNotBlank(thirdParty)) {
            //第三方登录加入登录类型,防止不同平台的三方账户重复
            qw.lambda().eq(BaseAccount::getAccountType, thirdParty);
        }
        account = baseUserAccountMapper.selectOne(qw);
        // 获取用户详细信息
        if (account != null) {
            accountDto = new UserAccount();
            BeanUtils.copyProperties(account, accountDto);
            accountDto.setUserProfile(baseUserService.getUserWithAuthoritiesById(account.getUserId()));
            //添加登录日志
            try {
                HttpServletRequest request = WebUtils.getHttpServletRequest();
                if (request != null) {
                    BaseUserAccountLogs log = new BaseUserAccountLogs();
                    log.setUserId(account.getUserId());
                    log.setAccount(account.getAccount());
                    log.setAccountId(String.valueOf(account.getAccountId()));
                    log.setAccountType(account.getAccountType());
                    log.setLoginAgent(request.getHeader(HttpHeaders.USER_AGENT));
                    addLoginLog(log);
                }
            } catch (Exception e) {
                log.error("添加登录日志失败:{}", e);
            }
        }
        return accountDto;
    }


    /**
     * 注册系统用户名账户
     *
     * @param userId
     * @param username
     * @param password
     */
    @Override
    public BaseAccount registerUsernameAccount(Long userId, String username, String password) {
        if (isExist(userId, username, BaseConstants.USER_ACCOUNT_TYPE_USERNAME)) {
            //已经注册
            return null;
        }
        password = Optional.ofNullable(password).orElse(CommonConstants.DEF_PWD);
        String encodePassword = passwordEncoder.encode(password);
        BaseAccount baseAccount = new BaseAccount(userId, username, encodePassword, BaseConstants.USER_ACCOUNT_TYPE_USERNAME);
        baseUserAccountMapper.insert(baseAccount);
        return baseAccount;
    }

    /**
     * 注册email账号
     *
     * @param userId
     * @param email
     * @param password
     */
    @Override
    public BaseAccount registerEmailAccount(Long userId, String email, String password) {
        if (!StringUtils.matchEmail(email)) {
            return null;
        }
        if (isExist(userId, email, BaseConstants.USER_ACCOUNT_TYPE_EMAIL)) {
            //已经注册
            return null;
        }
        password = Optional.ofNullable(password).orElse(CommonConstants.DEF_PWD);
        String encodePassword = passwordEncoder.encode(password);
        BaseAccount baseAccount = new BaseAccount(userId, email, encodePassword, BaseConstants.USER_ACCOUNT_TYPE_EMAIL);
        baseUserAccountMapper.insert(baseAccount);
        return baseAccount;
    }


    /**
     * 注册手机账号
     *
     * @param userId
     * @param mobile
     * @param password
     */
    @Override
    public BaseAccount registerMobileAccount(Long userId, String mobile, String password) {
        if (!StringUtils.matchMobile(mobile)) {
            return null;
        }
        if (isExist(userId, mobile, BaseConstants.USER_ACCOUNT_TYPE_MOBILE)) {
            //已经注册
            return null;
        }
        password = Optional.ofNullable(password).orElse(CommonConstants.DEF_PWD);
        String encodePassword = passwordEncoder.encode(password);
        BaseAccount baseAccount = new BaseAccount(userId, mobile, encodePassword, BaseConstants.USER_ACCOUNT_TYPE_MOBILE);
        baseUserAccountMapper.insert(baseAccount);
        return baseAccount;
    }


    /**
     * 重置用户密码
     *
     * @param userId
     * @param oldPassword
     * @param newPassword
     * @return
     */
    @Override
    public void resetPassword(Long userId, String oldPassword, String newPassword) {
        if (userId == null || StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword)) {
            return;
        }
        BaseUser userProfile = baseUserService.getUserById(userId);
        if (userProfile == null) {
            throw new OpenAlertException("用户信息不存在!");
        }
        if (CommonConstants.ROOT.equals(userProfile.getUserName())) {
            throw new OpenAlertException("默认用户不允许修改!");
        }
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getUserId, userId)
                .eq(BaseAccount::getAccount, userProfile.getUserName())
                .eq(BaseAccount::getAccountType, BaseConstants.USER_ACCOUNT_TYPE_USERNAME);
        BaseAccount baseAccount = baseUserAccountMapper.selectOne(queryWrapper);
        if (baseAccount == null) {
            return;
        }
        String oldPasswordEncoder = passwordEncoder.encode(oldPassword);
        if (!passwordEncoder.matches(baseAccount.getPassword(), oldPasswordEncoder)) {
            throw new OpenAlertException("原密码错误!");
        }
        baseAccount.setPassword(passwordEncoder.encode(newPassword));
        baseUserAccountMapper.updateById(baseAccount);
    }


    /**
     * 重置用户密码
     *
     * @param userId
     * @param password
     */
    @Override
    public void resetPassword(Long userId, String password) {
        if (userId == null || StringUtils.isBlank(password)) {
            return;
        }
        BaseUser userProfile = baseUserService.getUserById(userId);
        if (userProfile == null) {
            throw new OpenAlertException("用户信息不存在!");
        }
        if (CommonConstants.ROOT.equals(userProfile.getUserName())) {
            throw new OpenAlertException("默认用户不允许修改!");
        }
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getUserId, userId)
                .eq(BaseAccount::getAccount, userProfile.getUserName())
                .eq(BaseAccount::getAccountType, BaseConstants.USER_ACCOUNT_TYPE_USERNAME);
        BaseAccount baseAccount = baseUserAccountMapper.selectOne(queryWrapper);
        if (baseAccount == null) {
            return;
        }
        baseAccount.setPassword(passwordEncoder.encode(password));
        baseUserAccountMapper.updateById(baseAccount);
    }


    /**
     * 添加登录日志
     *
     * @param log
     */
    @Override
    public void addLoginLog(BaseUserAccountLogs log) {
        QueryWrapper<BaseUserAccountLogs> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseUserAccountLogs::getAccountId, log.getAccountId())
                .eq(BaseUserAccountLogs::getUserId, log.getUserId());
        int count = systemUserAccountLogsMapper.selectCount(queryWrapper);
        log.setLoginTime(new Date());
        log.setLoginNums(count + 1);
        systemUserAccountLogsMapper.insert(log);
    }

    /**
     * 检查是否已注册账号
     *
     * @param userId
     * @param account
     * @param accountType
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean isExist(Long userId, String account, String accountType) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getUserId, userId)
                .eq(BaseAccount::getAccount, account)
                .eq(BaseAccount::getAccountType, accountType);
        int count = baseUserAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }

    /**
     * 检测账号是否存在
     *
     * @param account
     * @param accountType
     * @param domain
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean isExist(String account, String accountType, String domain) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getAccount, account)
                .eq(BaseAccount::getAccountType, accountType)
                .eq(BaseAccount::getDomain, domain);
        int count = baseMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }

    @Override
    public Boolean isExist(String account, String accountType) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getAccount, account)
                .eq(BaseAccount::getAccountType, accountType);
        int count = baseUserAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean isExist(Long userId, String accountType) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getUserId, userId)
                .eq(BaseAccount::getAccountType, accountType);
        int count = baseUserAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Boolean checkByAccountName(String accountName) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(BaseAccount::getAccount, accountName);
        int count = baseUserAccountMapper.selectCount(queryWrapper);
        return count > 0 ? true : false;
    }
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public BaseAccount getUserAccount(String account, String accountType) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getAccount, account)
                .eq(false, BaseAccount::getAccountType, accountType);
        return baseUserAccountMapper.selectOne(queryWrapper);

    }

    /**
     * 解绑email账号
     *
     * @param userId
     * @param email
     * @return
     */
    @Override
    public void removeEmailAccount(Long userId, String email) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getUserId, userId)
                .eq(BaseAccount::getAccount, email)
                .eq(BaseAccount::getAccountType, BaseConstants.USER_ACCOUNT_TYPE_EMAIL);
        baseUserAccountMapper.delete(queryWrapper);
    }

    /**
     * 解绑手机账号
     *
     * @param userId
     * @param mobile
     * @return
     */
    @Override
    public void removeMobileAccount(Long userId, String mobile) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .eq(BaseAccount::getUserId, userId)
                .eq(BaseAccount::getAccount, mobile)
                .eq(BaseAccount::getAccountType, BaseConstants.USER_ACCOUNT_TYPE_MOBILE);
        baseUserAccountMapper.delete(queryWrapper);
    }

    /**
     * 删除账户
     *
     * @param userIds
     * @return
     */
    @Override
    public void removeAccount(Long[] userIds) {
        QueryWrapper<BaseAccount> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().in(BaseAccount::getUserId, userIds);
        baseUserAccountMapper.delete(queryWrapper);
    }

}
